/**
 * @FileName: BaseServiceImpl.java
 * @Package: service.impl
 * @author youshipeng
 * @created 2016/11/1 9:11
 * <p>
 * Copyright 2016 ziroom
 */
package top.swimmer.core.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import top.swimmer.core.dao.BaseMapper;
import top.swimmer.core.exception.WindstormExceptions;
import top.swimmer.core.model.BaseModel;
import top.swimmer.core.model.options.page.Pageable;
import top.swimmer.core.model.result.Results;
import top.swimmer.core.service.BaseService;
import top.swimmer.tools.common.Utils;

import java.lang.reflect.ParameterizedType;
import java.util.List;

/**
 * <p></p>
 *
 * <PRE>
 * <BR>	修改记录
 * <BR>-----------------------------------------------
 * <BR>	修改日期			修改人			修改内容
 * </PRE>
 *
 * @author youshipeng
 * @since 1.0
 * @version 1.0
 */
public abstract class BaseServiceImpl<MODEL extends BaseModel, MAPPER extends BaseMapper> implements BaseService<MODEL> {
    protected static final Void NO_RETURN = null;

    protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());

    @Autowired
    protected MAPPER mapper;

    protected Class<MODEL> modelClass;

    public BaseServiceImpl() {
        Class sonClass = (Class) getClass().getGenericSuperclass();
        modelClass = (Class<MODEL>) ((ParameterizedType) sonClass.getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @Override
    public MODEL create(MODEL model) {
        Utils.checkNull(model, "entity");

        try {
            mapper.create(model);
        } catch (Exception e) {
            LOGGER.error("Failed to create entity.", e);

            throw WindstormExceptions.INSTANCE.createFailed(getModelClassName());
        }

        return model;
    }

    @Override
    public MODEL createOrUpdate(MODEL model) {
        Utils.checkNull(model, "entity");

        try {
            if (model.getId() != null) {
                mapper.update(model.getId(), model);
            } else {
                mapper.create(model);
            }
        } catch (Exception e) {
            LOGGER.error("Failed to create or update entity.", e);

            throw WindstormExceptions.INSTANCE.createFailed(getModelClassName());
        }

        return model;
    }

    @Override
    public MODEL get(Integer id) {
        Utils.checkNull(id, "entityId");

        MODEL entity = (MODEL) mapper.get(id);

        if (entity == null)
            throw WindstormExceptions.INSTANCE.notFound(getModelClassName(), id);

        return entity;
    }

    @Override
    public MODEL update(Integer id, MODEL model) {
        Utils.checkNull(id, "entityId");
        Utils.checkNull(model, "entity");

        if (model.getId() != null && !model.getId().equals(id)) {
            throw new IllegalArgumentException("Entity id does match.");
        }

        try {
            mapper.update(id, model);
        } catch (Exception e) {
            LOGGER.error("Failed to update entity.", e);

            throw WindstormExceptions.INSTANCE.updateFailed(getModelClassName(), id);
        }

        return get(id);
    }

    @Override
    public void delete(Integer id) {
        Utils.checkNull(id, "entityId");

        try {
            mapper.delete(id);
        } catch (Exception e) {
            LOGGER.error("Failed to delete entity.", e);

            throw WindstormExceptions.INSTANCE.deleteFailed(getModelClassName(), id);
        }
    }

    @Override
    public void softDelete(Integer id) {
        try {
            MODEL entity = get(id);
            entity.setDeleted(true);
            update(id, entity);
        } catch (Exception e) {
            LOGGER.error("Failed to soft delete entity.", e);

            throw WindstormExceptions.INSTANCE.softDeleteFailed(getModelClassName(), id);
        }
    }

    @Override
    public boolean exists(Integer id) {
        Utils.checkNull(id, "entityId");

        try {
            return mapper.exists(id);
        } catch (Exception e) {
            LOGGER.error("Failed to query entity.", e);

            throw WindstormExceptions.INSTANCE.queryFailed();
        }
    }

    @Override
    public List<MODEL> getAll() {
        try {
            return mapper.getAll();
        } catch (Exception e) {
            LOGGER.error("Failed to get all entities.", e);

            throw WindstormExceptions.INSTANCE.queryFailed();
        }
    }

    @Override
    public Results<MODEL> getAllByPagination(Pageable options) {
        try {
            return mapper.getAllByPagination(options);
        } catch (Exception e) {
            LOGGER.error("Failed to get all entities by pagination.", e);

            throw WindstormExceptions.INSTANCE.queryFailed();
        }
    }

    @Override
    public List<MODEL> batchGet(List<Integer> ids) {
        try {
            return mapper.batchGet(ids);
        } catch (Exception e) {
            LOGGER.error("Failed to batch get entities.", e);

            throw WindstormExceptions.INSTANCE.queryFailed();
        }
    }

    protected String getModelClassName() {
        return modelClass.getSimpleName();
    }
}